//
// Created by ziya on 2021/1/14.
//

#include "../include/javaThread.h"

/**
 * 对应Java代码：stack-engine-java#com.neihedaren.version.one.ExampleOne
 *
0 bipush 10
2 istore_0
3 bipush 20
5 istore_1
6 iload_0
7 iload_1
8 iadd
9 ireturn
 */
static int runAdd(JavaThread* thread) {
    // 创建栈帧
    StackFrame stackFrame(2, 3);

    // 栈帧入虚拟机栈
    thread->stack()->stackFrames()->push(stackFrame);

    // bipush 10
    stackFrame.operandStack()->pushInt(10);

    // istore_0
    stackFrame.localVariableTable()->storeInt(0, stackFrame.operandStack()->popInt());

    // bipush 20
    stackFrame.operandStack()->pushInt(20);

    // istore_1
    stackFrame.localVariableTable()->storeInt(1, stackFrame.operandStack()->popInt());

    // iload_0
    stackFrame.operandStack()->pushInt(stackFrame.localVariableTable()->getIntSlot(0));

    // iload_1
    stackFrame.operandStack()->pushInt(stackFrame.localVariableTable()->getIntSlot(1));

    // iadd
    int v1 = stackFrame.operandStack()->popInt();
    int v2 = stackFrame.operandStack()->popInt();

    INFO_PRINT("v1 + v2 = %d\n", v1 + v2);

    // 销毁栈帧
    thread->stack()->stackFrames()->pop();

    return v1 + v2;
}

/**
 * 对应Java代码：stack-engine-java#com.neihedaren.version.one.ExampleOne
 *
0 bipush 100
2 istore_1
3 invokestatic #2 <com/neihedaren/version/one/ExampleOne.add>
6 istore_2
7 iload_1
8 iload_2
9 isub
10 istore_3
11 return
 */
static void runMain(JavaThread* thread) {
    StackFrame stackFrame(2, 3);

    thread->stack()->stackFrames()->push(stackFrame);

    // bipush 100
    stackFrame.operandStack()->pushInt(100);

    // istore_1
    stackFrame.localVariableTable()->storeInt(1, stackFrame.operandStack()->popInt());

    /**
     * invokestatic
     *
     * 如果有返回结果，记得入栈，这个容易忘记
     */
     stackFrame.operandStack()->pushInt(runAdd(thread));

    // istore_2
    stackFrame.localVariableTable()->storeInt(2, stackFrame.operandStack()->popInt());

    // iload_1
    stackFrame.operandStack()->pushInt(stackFrame.localVariableTable()->getIntSlot(1));

    // iload_2
    stackFrame.operandStack()->pushInt(stackFrame.localVariableTable()->getIntSlot(2));

    // isub
    int v1 = stackFrame.operandStack()->popInt();
    int v2 = stackFrame.operandStack()->popInt();
    INFO_PRINT("%d\n", v2 - v1);

    // istore_3
    stackFrame.operandStack()->pushInt(v2 - v1);

    thread->stack()->stackFrames()->pop();
}

void JavaThread::run() {
    runMain(this);

#ifdef DEBUG
    cout << "stackFrame size = " << stack()->stackFrames()->size() << endl;
#endif
}